---
title: App version management
description: Learn about different version types and how to manage them remotely or locally.
---

import { ContentSpotlight } from '~/ui/components/ContentSpotlight';
import { Terminal } from '~/ui/components/Snippet';

Android and iOS each expose two values to identify the version of an app: the version visible in stores (user-facing version) and the version visible only to developers (developer-facing build version). This guide explains how you can manage those versions remotely or locally.

## App versions

In Expo projects, the following properties can be used to define app versions in the [app config](/workflow/configuration/) file.

| Property                                                          | Description                                                                                                                                                                                    |
| ----------------------------------------------------------------- | ---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| [`version` ](/versions/latest/config/app/#version)                | The user-facing version visible in stores. On Android, it represents `versionName` name in **android/app/build.gradle**. On iOS, it represents `CFBundleShortVersionString` in **Info.plist**. |
| [`android.versionCode`](/versions/latest/config/app/#versioncode) | The developer-facing build version for Android. It represents `versionCode` in **android/app/build.gradle**.                                                                                   |
| [`ios.buildNumber`](/versions/latest/config/app/#buildnumber)     | The developer-facing build version for iOS. It represents `CFBundleVersion` in **Info.plist**.                                                                                                 |

### Using app versions in your app

To show the user-facing version inside your app, you can use [`Application.nativeApplicationVersion`](/versions/latest/sdk/application/#applicationnativeapplicationversion) from the `expo-application` library.

To show the developer-facing build version inside your app, you can use [`Application.nativeBuildVersion`](/versions/latest/sdk/application/#applicationnativebuildversion) from the `expo-application` library.

## Recommended workflow

### User-facing version

When you are doing a production release, the user-facing version should be explicitly set and updated by you. You can update the `version` property in app config when production build is submitted to the app stores. This also applies if your project uses `expo-updates` with an automatic runtime version policy. This marks the beginning of a new development cycle for a new version of your app. Learn more about [deployment patterns](/eas-update/deployment-patterns).

### Developer-facing build version

For developer-facing build version, you can set them to autoincrement on every build. This will help you avoid making manual changes to the project every time you upload a new archive on Play Store testing channels or TestFlight. One common cause for app store rejections is submitting a build with a duplicate version number. It happens when a developer forgets to increment the developer-facing build version number before creating a new build.

EAS Build can help manage developer-facing build versions automatically by incrementing these versions for you if you opt into using the [`remote` version source](#remote-version-source). The default behavior is to use a `local` version source, which means you control versions manually in their respective config files.

## Remote version source

EAS servers can store and manage your app's developer-facing build version (`android.versionCode` and `ios.buildNumber`) remotely. You can achieve this by setting `cli.appVersionSource` to `remote` in **eas.json**. Then, under the `production` build profile, you can set the `autoIncrement` property to `true`.

```json eas.json
{
  "cli": {
    /* @info The app version source is set to <CODE>remote</CODE> to store and manage the version of your app. */
    "appVersionSource": "remote"
    /* @end */
  },
  "build": {
    "development": {
      /* @hide ... */
      /* @end */
    },
    "preview": {
      /* @hide ... */
      /* @end */
    },
    "production": {
      /* @info The <CODE>autoIncrement</CODE> property is set to <CODE>true</CODE> to automatically increment the <CODE>android.versionCode</CODE> and <CODE>ios.buildNumber</CODE> values. */
      "autoIncrement": true
      /* @end */
    }
  }
  /* @hide ... */ /* @end */
}
```

The remote version is initialized with the value from the local project. For example, if you have `android.versionCode` set to `1` in app config, when you create a new build using the remote version source, it will auto increment to `2`. However, if you do not have build versions set in your app config, the remote version will initialize with `1` when the first build is created.

When the `remote` version property is enabled inside **eas.json**, the build version values stored in app config are ignored and not updated when the version is incremented remotely. The remote version source values are set on the native project when running a build, which is considered the source of truth for these values. You can safely remove these values from your app config.

### Video walkthrough

<ContentSpotlight url="https://www.youtube.com/embed/Gk7RHDWsLsQ" />

### Syncing already defined versions to remote

There are different scenarios where you already have versions set up for your project and want to increment from those versions when you create a new EAS Build. However, these existing versions might not be synced remotely with EAS. Some of these scenarios are:

- You have already published your app in the app stores and want to continue using the same version numbers.
- EAS CLI is not able to detect what version the app is on.
- For any other reason, you have versions explicitly set, such as inside your app config.

In these scenarios, you can sync the current version to EAS Build using the EAS CLI using the following steps:

- In the terminal window, run the following command:

  <Terminal cmd={['$ eas build:version:set']} />

- Select the platform (Android or iOS) when prompted.
- When prompted **Do you want to set app version source to remote now?**, select **yes**. This will set the `cli.appVersionSource` to `remote` in **eas.json**.
- When prompted **What version would you like to initialize it with?**, enter the last version number that you have set in the app stores.

After these steps, the app versions will be synced to EAS Build remotely. You can now set `build.production.autoIncrement` to `true` in **eas.json**. When you create a new production build, the `versionCode` and `buildNumber` will be automatically incremented.

### Syncing versions from remote to local

To build your project locally in Android Studio or Xcode using the same version stored remotely on EAS, update your local project with the remote versions using the following command:

<Terminal cmd={['$ eas build:version:sync']} />

### Limitations

- `eas build:version:sync` command on Android does not support bare projects with multiple flavors. However, the rest of the remote versioning functionality should work with all projects.
- `autoIncrement` does not support the `version` option.
- It's not supported if you are using EAS Update and runtime policy set to `"runtimeVersion": { "policy": "nativeVersion" }`. For similar behavior, use the `"appVersion"` policy instead.

## Local version source

By default, the source of truth for project versions is the local project source code itself. In this case, EAS does not write to the project. It reads the app version values and builds projects as they are. You can opt in to auto incrementing versions locally by setting the `autoIncrement` option on a build profile.

```json eas.json
{
  "cli": {
    /* @end */
  },
  "build": {
    "development": {
      /* @hide ... */
      /* @end */
    },
    "preview": {
      /* @hide ... */
      /* @end */
    },
    "production": {
      /* @info The <CODE>autoIncrement</CODE> property is set to <CODE>true</CODE> to automatically increment the <CODE>android.versionCode</CODE> and <CODE>ios.buildNumber</CODE> values. */
      "autoIncrement": true
      /* @end */
    }
  }
  /* @hide ... */ /* @end */
}
```

In the case of [existing React Native projects](/bare/overview/), the values in native code take precedence. The libraries `expo-constants` and `expo-updates` read values from the app config file. If you rely on version values from a manifest, you should keep them in sync with native code. Keeping these values in sync is especially important if you are using EAS Update with the runtime policy set to `"runtimeVersion": { "policy": "nativeVersion" }`, because mismatched versions may result in the delivery of updates to the wrong version of an application. We recommend using [`expo-application`](/versions/latest/sdk/application/#constants) to read the version instead of depending on values from app config.

### Limitations

- With `autoIncrement`, you need to commit your changes on every build if you want the version change to persist. This can be difficult to coordinate when building on CI.
- `autoIncrement` is not supported if you are using a dynamic config file (such as **app.config.js**).
- For existing React Native projects with Gradle configuration that supports multiple flavors, EAS CLI is not able to read or modify the version, so `autoIncrement` option is not supported, and versions will not be listed in the build details page on [expo.dev](https://expo.dev).
